home *** CD-ROM | disk | FTP | other *** search
/ Merciful 2 / Merciful - Disc 2.iso / software / a / alliancedoc's03.dms / alliancedoc's03.adf / CHAP5_5.doc.pp / CHAP5_5.doc
Text File  |  1992-02-22  |  50KB  |  1,516 lines

  1.   ________________________________________________________________________
  2.  /                                      \
  3. | ALLIANCE Presents : Amiga Graphics Inside and Out.                   |
  4. |              The complete Book from Abacus.               |
  5. |                                           |
  6. | Typed By          : Razor Blade.                       |
  7. | Supplied By       : Viper.                           |
  8. |                                        |
  9. | ALLIANCE ARE : Alchemist, Aramis, Barbarian, CI/\RS, Chaos, Glitch, Mit, |
  10. |         Raistlin, Razor Blade, ShadowFax and Viper.               |
  11. |                                           |
  12.  \________________________________________________________________________/
  13.  
  14.  
  15. /\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\/\\
  16. >                                      <
  17. >       CALL OUR WORLD HQ N-O-W : UNKNOWN PLEASURES : +44 823 322891      <
  18. >                                      <
  19. \//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//\//
  20.  
  21.  
  22.  
  23.         
  24.         
  25. 5.5 DESIGNING YOUR OWN FONTS.
  26.  
  27. By now you should know enough about the standard Amiga fonts. We will now
  28. move onto the last and most difficult section: defining a completely 
  29. original font.
  30.         
  31. In order to do this you need to know about the contruction of a font. At
  32. the beginning of this chapter we introduced you to the data structure named
  33. TextFont. Before continuing with this data structure, we will present some
  34. of the peculiarities of an Amiga font.
  35.         
  36. Basically, there are two different font forms for the Amiga:
  37.         
  38. a.) Normal fonts.
  39.         
  40. b.) Proportional fonts.
  41.         
  42. A typical font consists of characters that have equal height and width.
  43. Proportional font characters also have equal heights but inidividual 
  44. widths.
  45.  
  46. You need a maximum of 4 memory blocks to define a font.
  47.  
  48.         charData
  49.         charLoc
  50.         charSpace
  51.         charKern
  52.  
  53. charData contains the actual definition of a character in the font. This 
  54. refers to the bitpacked character information. Since an Amiga character can
  55. be any character width that you select, it is wastful to store the data
  56. for every character in byte form. Th Amiga stores the characters data as
  57. follows:
  58.         
  59. Let's start with the two characters below. A "." represents an unset pixel
  60. and a "*" represents a set pixel.
  61.         
  62.         ....*....      ****.
  63.         ...*.*...      *...*
  64.         ..*...*..      *...*
  65.         .*.....*.      ****.
  66.         *********      *...*
  67.         *.......*      *...*
  68.         *       *      ****
  69.         
  70.         
  71.                                 PAGE 234
  72.         
  73. -----------------------------------------------------------------------------
  74.         
  75.         
  76. These two characters have different widths and could be from a proportional
  77. font. The Amiga creates a bit-row, one after the other of all the characters
  78. in a font. If our font contained only the characters above then charData
  79. would look like this:
  80.         
  81.         1. row:   ....*....****.
  82.         2. row:   ...*.*...*...*
  83.         3. row:   ..*...*..*...*
  84.         4. row:   .*.....*.****.
  85.         5. row:   **********...*
  86.         6. row:   *.......**...*
  87.         7. row:   *.......*****.
  88.         
  89. The individual rows are then written one after the other into the memory
  90. block:
  91.         
  92.      charData: ....*....****....*.*...*...*..*...*..*...* etc ...
  93.         
  94. This storage methoid is very efficient but has one problem. We need to 
  95. get the characters out of the bits. This is why there is a memory block,
  96. call charLoc. This block contains two words (two-byte fields) for every
  97. character in the font. The first word contains the bit count from the
  98. start of a row to the bit information for the character. The second word
  99. contains the bit count of the character. For the two characters in our 
  100. example it look like this:
  101.         
  102.         charLoc:  0,9  9,5
  103.         
  104. The first character begins zero bits from the beginning of the data row and
  105. is nine pixels wide. The second charcter begins 9 bits after the start of 
  106. the data row and is five pixels wide. This is the definition for all seven 
  107. rows of our characters.
  108.         
  109. Another problem is getting from one charData row to the next. The field
  110. MODULO from the Textfont structure is used to do this. The length, in 
  111. bytes, of the data row is stored here. To get yor next row, add this value
  112. to the current address of the data row.
  113.  
  114. The data field CharData contains only the basic information for the current
  115. character. So, to separate the characters on the screen, we need to insert 
  116. some space between them. The field charSpace contains the real character 
  117. width, in pixels. For example:
  118.  
  119.         charSpace: 11,7
  120.  
  121. The first character is eleven pixels wide and the second is seven.
  122.         
  123. There is one last problem, charSpace sets the actual character width. For
  124. the first character in our example, this is eleven pixels.
  125.  
  126.  
  127.                                 PAGE 235
  128.  
  129. -----------------------------------------------------------------------------
  130.  
  131.         
  132.         ...........
  133.         ...........
  134.         ...........
  135.         ...........
  136.         ...........
  137.         ...........
  138.         ...........
  139.         
  140. This is a problem because the character itself is only 9 pixels wide.
  141. So the position at which this field should begin displaying the character 
  142. is still unknown. The block, charKern contains, for every character, a 
  143. word that defines, in bits, the distancee from the left edge of the field
  144. where the character should be displayed. Again an example:
  145.         
  146.         charKern:  1,2
  147.         
  148. This displays our characters on screen like this:
  149.         
  150.         .....*.....    ..****.
  151.         ....*.*....    ..*...*
  152.         ...*...*...    ..*...*
  153.         ..*.....*..    ..****.
  154.         .*********.    ..*...*
  155.         .*.......*.    ..*...*
  156.         .*.......*.    ..****.
  157.         
  158.         Space = 11     Space = 7
  159.         Kern  = 1      Kern  = 2
  160.         Width = 9      Width = 5
  161.         
  162.         
  163.                 --------------------------------------------
  164.         
  165. 5.5.1 READING THE FONT GENERATOR.
  166.         
  167. By using the information provided above, we can access an existing font
  168. and read it. You can also get the data for a specific character and read
  169. it.
  170.         
  171. The address of the TextFont structure for a font that is currently open
  172. is found in the RastPort.
  173.         
  174.         font& = PEEKL(WINDOW(8)+52)
  175.         
  176. You will find the required pointer to the memory block there (see section 
  177. 5.1):
  178.         
  179.         
  180.                                 PAGE 236
  181.  
  182. -----------------------------------------------------------------------------
  183.  
  184.         
  185. Here is the font reader program:
  186.  
  187.         '##########################################
  188.         '#
  189.         '# Section: 5.5.1
  190.         '# Program: Font Readerr
  191.         '# Date   : 04/11/87
  192.         '# Author : tob
  193.         '# Version: 1.0
  194.         '#
  195.         '###########################################
  196.         
  197.         ' Reads the currently active font and displays the
  198.         ' decoded information in different sized variations.
  199.         
  200.         PRINT "Searching for .bmap files...."
  201.         
  202.         'GRAPHICS library
  203.         DECLARE FUNCTION OpenFont& LIBRARY
  204.         'SetFont()
  205.         'CloseFont()
  206.         
  207.         LIBRARY "graphics.library"
  208.         
  209.         init:   '* Variables
  210.             DIM SHARED  char$(256)
  211.             g%  = 12 'Box size
  212.             CLS
  213.         
  214.             FOR demo% = 32 TO 255
  215.                 Matrix demo%
  216.                 CLS
  217.                 TopazON
  218.                 PRINT "Character: ASCII ";demo%;" = ";CHR$(demo%)
  219.                 FOR show% = 1 TO height%
  220.                     LOCATE show%+2,1
  221.                     PRINT char$(show%)
  222.                     FOR ex% = 1 TO LEN(char$(show%))
  223.                         z$ = MID$(char$(show%),ex%,1)
  224.                         IF z$ = "*" THEN
  225.                             kolor% = 2
  226.                         ELSEIF z$ = "." THEN
  227.                             kolor% = 1
  228.                         ELSEIF z$ = "," THEN
  229.                             kolo% = 3
  230.                         END IF
  231.                         LINE (300+ex%*g%,show%*g%)-(300+ex%*g%+g%,show%
  232.         *g%+g%),kolor%,bf
  233.                         LINE (500+ex%*2,show%*2)-(500+ex%*2+2,show%*2+2),
  234.         kolor%,bf
  235.                     NEXT ex%
  236.         
  237.         
  238.                                 PAGE 237
  239.         
  240. -----------------------------------------------------------------------------
  241.         
  242.         
  243.                 NEXT show%
  244.                 TopazOFF
  245.             NEXT demo%
  246.             
  247.             END
  248.             
  249.     SUB Matrix(code%) STATIC
  250.         SHARED height%
  251.         
  252.         f.1%          =0
  253.         f.2%          =0
  254.         font%         =PEEKL(WINDOW(8)+52)
  255.         charData&     =PEEKL(font&+34)
  256.         charLoc&      =PEEKL(font&+40)
  257.         charSpace&    =PEEKL(font&+44)
  258.         charKern&     =PEEKL(font&+48)
  259.         modulo%       =PEEKW(font&+38)
  260.         
  261.         IF charSpace& = 0 THEN f.1% = 1
  262.         IF charKern&  = 0 THEN f.2% = 1
  263.         
  264.         height%       = PEEKW(font&+20)
  265.         
  266.         loASCII       = PEEK(font&+32)
  267.         hiASCII       = PEEK(font&+33)
  268.         
  269.         IF code%<loASCII% OR code%>hiASCII THEN
  270.             PRINT "ASCII code ";code%;" not in font"
  271.         END IF
  272.         
  273.         'Decoding information.
  274.         offset%    = code% - loASCII%
  275.         offset.bit&= PEEKW(charLoc&+4*offset%)
  276.         offset.byte%= INT(offset.bit&/8)
  277.         offset.bit% = offset.bit& - (8*offset.byte%)
  278.         char.width% = PEEKW(charLoc&+4*offset%+2)
  279.         IF f.1% = 0 THEN
  280.             char.space% = PEEKW(charSpace&+2*offset%)
  281.         END IF
  282.         IF f.2% = 0 THEN
  283.             char.kern%  = PEEKW(charKern&+2*offset%)
  284.         END IF
  285.  
  286.         'Read data
  287.         FOR loop1% = 1 TO height%
  288.             char$(loop1%) = ""
  289.             IF f.2% = 0 THEN
  290.                 IF char.kern%>0 THEN
  291.                     char$(loop1%)=STRING$(char.kern%,",")
  292.                 END IF
  293.             END IF
  294.             linedata& = PEEK(charData+offset.byte%)
  295.             counter% = 7-offset.bit%
  296.             FOR loop2% = 1 TO char.width%
  297.                 IF (linedata& AND 2^counter%)<>0 THEN
  298.                     linedata&   = linedata& - 2^counter%
  299.         
  300.         
  301.                                 PAGE 238
  302.  
  303. -----------------------------------------------------------------------------
  304.  
  305.  
  306.                     char$(loop1%) = char$(loop1%)+"*"
  307.                 ELSE
  308.                     char$(loop1%) = char$(loop1%)+"."
  309.                 END IF
  310.                 counter% = counter% - 1
  311.                 IF counter% < 0 THEN
  312.                     offset.long%  = offset.long%+1
  313.                     linedata&     = PEEK(charData&+offset.byte%+
  314.    offset.long%)
  315.                     counter%   = 7
  316.                 END IF
  317.             NEXT loop2%
  318.             offset.long% = 0
  319.             charData&  = charData&+modulo%
  320.             IF f.2% = 0 THEN 
  321.                 char.diff% = char.space%-char.width%-char.kern%
  322.             ELSEIF f.2% = 0 THEN
  323.                 char.diff% = char.space%-char.width%
  324.             END IF
  325.             IF char.diff%>0 THEN
  326.                 char$(loop1%)=char$(loop1%)+STRING$(char.diff%,",")
  327.             END IF
  328.         NEXT loop1%
  329.     END SUB
  330.         
  331.     SUB TopazOn STATIC
  332.         SHARED font&,font.old&
  333.         font$        = "topaz.font"+CHR$(0)
  334.         textAttr&(0) = SADD(font$)
  335.         font.old&    = PEEKL(WINDOW(8)+52)
  336.         font&        = OpenFont&(VARPTR(textAttr&(0)))
  337.         CALL SetFont(WINDOW(8),font&)
  338.     END SUB
  339.         
  340.     SUB TopazOFF STATIC
  341.         SHARED font&,font.old&
  342.         CALL CloseFont(font&)
  343.         CALL SetFont(WINDOW(8),font.old&)
  344.     END SUB
  345.  
  346.  
  347. This program reads the currently active font. In most cases, this is one of
  348. the two ROM fonts. To see something really interesting first load one of
  349. the disk fonts like sapphire.
  350.  
  351. All the possible characters of the font are represented on the screen in 
  352. three ways: 1.) using "*" and ".", 2.) as large graphics, 3.) as small 
  353. graphics.
  354.  
  355. The graphics use three different colours. The data area define by charData
  356. is white and all the set pixels are black. The additional pixels defined
  357. by charSpace and CharKern are displayed in Orange.
  358.  
  359.  
  360.                                 PAGE 239
  361.  
  362. -----------------------------------------------------------------------------
  363.  
  364.  
  365. However, proportional fonts will not display any orange because they do not
  366. use charSpace and charKern.
  367.         
  368. The following is information about the program:
  369.         
  370. The heart of the program is the SUB matrix. This routine handles the 
  371. difficult task of reading the font but can also be used for other purposes.
  372. Here is the call:
  373.  
  374.         Matrix ascii.code%
  375.  
  376.         ascii.code%: ASCII code of the character (0-255)
  377.         
  378. or:
  379.         Matrix CINT(ASC(z$))
  380.         
  381.         z$: the desired character.
  382.         
  383. In addition, there are the SUB programs TopazOn and TopazOff, which switch 
  384. the currently active system font on and off. By using them, you are able to
  385. display comments between the font data that are independant of the active
  386. font being read and displayed.
  387.         
  388. An explanation of how the SUB Matrix functions is found in section 5.5
  389.         
  390.         
  391.                 --------------------------------------------
  392.         
  393. 5.5.2 BIG TEXT: ENLARGING TEXT.
  394.         
  395. This application demonstrates the adaptability of the read routine Matrix,
  396. from our previous example. Matrix helps the SUB BigText create text of any
  397. desired size on the screen.
  398.         
  399. This is the call:
  400.                 
  401.                 BigText text$,sixe%,kolor%
  402.         
  403.                 text$:    Text to display.
  404.                 size%:    Enlargin factor (1-...)
  405.                 kolor%:   Text color.
  406.         
  407.         
  408.                                 PAGE 240
  409.         
  410. -----------------------------------------------------------------------------
  411.         
  412.         
  413.         '#####################################
  414.         '#        
  415.         '# Section: 5.5.2
  416.         '# Program: Enlarge text.
  417.         '# Date   : 04/11/87
  418.         '# Author : tob
  419.         '# Version: 1.0
  420.         '#
  421.         '#####################################
  422.         
  423.         ' Enlarges any desired text. The text is enlarged in the 
  424.         ' style of the currently active font.
  425.         
  426.         init:
  427.             '* Variables
  428.             DIM SHARED char$(256)
  429.             BigText "Hello",15,2
  430.             BigText "Commodore AMIGA",4,3
  431.             LOCATE 3,1
  432.             BigText "small",1,1
  433.             BigText "larger",2,1
  434.             BigText "Larger Yet!",3,1
  435.             BigText "GIGANTIC!",8,3
  436.             END
  437.             
  438.             
  439.     SUB BigText(text$,size%,kolor%) STATIC
  440.             SHARED height%,char.kern%,char.width%
  441.             SHARED char.space%
  442.         
  443.             o.xo%  = 0
  444.             z.x%   = PEEKW(WINDOW(8)+58)
  445.             z.y%   = PEEKW(WINDOW(8)+58)
  446.             y%     = CSRLIN*z.y%
  447.             x%     = POS(0)*z.x%
  448.             
  449.             FOR loop1% = 1 TO LEN(text$)
  450.                 z$ = MID$(text$,loop1%,1)
  451.                 Matrix CINT(ASC(z$))
  452.                 o.xo% = o.xo% + char.kern%*size%
  453.                 FOR loop2% = 1 TO height%
  454.                     FOR loop3% = 1 TO LEN(char$(loop2%))
  455.                         m$ = MID$(char$(loop2%),loop3%,1)
  456.                         IF m$ = "" THEN
  457.                             o.x% = x%+o.xo%+loop3%*size%
  458.                             o.y% = y%+loop2%*size%
  459.                             LINE (o.x%,o.y%)-(o.x%+size%,o.y%+size%),
  460.     kolor%,bf
  461.                         END IF
  462.                     NEXT loop3%
  463.                 NEXT loop2%
  464.                 rest% = char.space%-char.width%-char.kern%
  465.                 IF rest% < 0 THEN rest% = 0
  466.                 o.xo% = o.xo%+char.width%*size%+rest%*size%
  467.             NEXT loop1%
  468.             PRINT 
  469.     END SUB
  470.         
  471.         
  472.         
  473.                                 PAGE 241
  474.         
  475. -----------------------------------------------------------------------------
  476.         
  477.         
  478.     SUB Matrix(code%) STATIC
  479.         SHARED height%, char.kern%, char.width%
  480.         SHARED char.space%
  481.         
  482.         f.1%          =0
  483.         f.2%          =0
  484.         font%         =PEEKL(WINDOW(8)+52)
  485.         charData&     =PEEKL(font&+34)
  486.         charLoc&      =PEEKL(font&+40)
  487.         charSpace&    =PEEKL(font&+44)
  488.         charKern&     =PEEKL(font&+48)
  489.         modulo%       =PEEKW(font&+38)
  490.         
  491.         IF charSpace& = 0 THEN f.1% = 1
  492.         IF charKern&  = 0 THEN f.2% = 1
  493.         
  494.         height%       = PEEKW(font&+20)
  495.         
  496.         loASCII       = PEEK(font&+32)
  497.         hiASCII       = PEEK(font&+33)
  498.         
  499.         IF code%<loASCII% OR code%>hiASCII THEN
  500.             PRINT "ASCII code ";code%;" not in font"
  501.         END IF
  502.         
  503.         'Decoding information.
  504.         offset%    = code% - loASCII%
  505.         offset.bit&= PEEKW(charLoc&+4*offset%)
  506.         offset.byte%= INT(offset.bit&/8)
  507.         offset.bit% = offset.bit& - (8*offset.byte%)
  508.         char.width% = PEEKW(charLoc&+4*offset%+2)
  509.         z.b% = char.width%
  510.         IF f.1% = 0 THEN
  511.             char.space% = PEEKW(charSpace&+2*offset%)
  512.             z.b%   = char.space%
  513.         END IF
  514.         IF f.2% = 0 THEN
  515.             char.kern%  = PEEKW(charKern&+2*offset%)
  516.         END IF
  517.         
  518.         'Read data
  519.         FOR loop1% = 1 TO height%
  520.             char$(loop1%) = ""
  521.             IF f.2% = 0 THEN
  522.                 IF char.kern%>0 THEN
  523.                     char$(loop1%)=STRING$(char.kern%,",")
  524.                 END IF
  525.             END IF
  526.             linedata& = PEEK(charData+offset.byte%)
  527.             counter% = 7-offset.bit%
  528.             FOR loop2% = 1 TO char.width%
  529.                 IF (linedata& AND 2^counter%)<>0 THEN
  530.                     linedata&   = linedata& - 2^counter%
  531.                     char$(loop1%) = char$(loop1%)+"*"
  532.                 ELSE
  533.         
  534.         
  535.                                 PAGE 242
  536.         
  537. -----------------------------------------------------------------------------
  538.  
  539.  
  540.  
  541.                     char$(loop1%) = char$(loop1%)+"."
  542.                 END IF
  543.                 counter% = counter% - 1
  544.                 IF counter% < 0 THEN
  545.                     offset.long%  = offset.long%+1
  546.                     linedata&     = PEEK(charData&+offset.byte%+
  547.    offset.long%)
  548.                     counter%   = 7
  549.                 END IF
  550.             NEXT loop2%
  551.             offset.long% = 0
  552.             charData&  = charData&+modulo%
  553.             IF f.2% = 0 THEN 
  554.                 char.diff% = char.space%-char.width%-char.kern%
  555.             ELSEIF f.2% = 0 THEN
  556.                 char.diff% = char.space%-char.width%
  557.             END IF
  558.             IF char.diff%>0 THEN
  559.                 char$(loop1%)=char$(loop1%)+STRING$(char.diff%,",")
  560.             END IF
  561.         NEXT loop1%
  562.     END SUB
  563.         
  564.         
  565. The matrix routine had to be changed slightly so that BigText could 
  566. position the text properly. In order to do this, we added a few more 
  567. parameters to the SHARED assignment at the beginning of the SUB.
  568.         
  569.         
  570.                 --------------------------------------------
  571.         
  572.         
  573. 5.5.3 A FIXED WIDTH FONT GENERATOR.
  574.         
  575. Now that you are more comfortable with the pointers and contents of a font,
  576. we will proceed to our main project, a character generator.
  577.         
  578. You have seen how difficult it is to define and manage a proportional font.
  579. Because of this, our first character generator is a fixed width generator 
  580. which creates characters with identical widths.
  581.         
  582. To further simplify this process, our characters will have a set size of 
  583. 8*8 pixels like the ROM font "topaz 8". Since this size has a one byte 
  584. offset, it's easy to store and handle the character data in charData.
  585.         
  586. Before we discuss the details of the program, here is the program listing:
  587.         
  588.         
  589.         
  590.                                 PAGE 243
  591.         
  592. -----------------------------------------------------------------------------
  593.         
  594.         
  595.         '############################################
  596.         '#
  597.         '# Section: 5.5.3
  598.         '# Program: Fixed-width font generator.
  599.         '# Date   : 04/12/87
  600.         '# Author : tob
  601.         '# Version: 1.0
  602.         '#
  603.         '##############################################
  604.         
  605.         ' This program makes possible the creation of a 
  606.         ' different font. Every character has a set size.
  607.         ' of 8*8 pixels. Each character can be freely defined
  608.         ' as required. All undefined characters will default to the
  609.         ' standard ROM font (topaz 8). Unavailable characters will be
  610.         ' indicated by the 'unprintable character' symbol.
  611.         
  612.         PRINT "Searching for .bmap file ......"
  613.         
  614.         'GRAPHICS-library
  615.         DECLARE FUNCTION OpenFont& LIBRARY
  616.         'CloseFont()
  617.         'SetFont()
  618.         'AddFont()
  619.         
  620.         'EXEC-library
  621.         DECLARE FUNCTION AllocMem& LIBRARY
  622.         'FreeMem()
  623.         'CopyMem()
  624.         
  625.         LIBRARY "graphics.library"
  626.         LIBRARY "exec.library"
  627.         
  628.         init:
  629.             CLS
  630.             '* Generate character set
  631.             '* Call :
  632.             '*    MakePrgFont "name",asciiLo%,asciiHi%
  633.             
  634.             MakePrgFont "tobi",22,200
  635.             MakePrgFont "ralfi",60,122
  636.         
  637.             '* Call:
  638.             '*     ActivateFont "name"
  639.             
  640.             ActivateFont "tobi"
  641.         
  642.             '* Define new font.
  643.             '* Call:
  644.             '*     NewD "char",row%,"definition"
  645.             '*     row%:  0....7 definition: *=set pixel
  646.         
  647.             NewD "A",0,"......*."
  648.             NewD "A",1,".....**."
  649.             NewD "A",2,"....***."
  650.             NewD "A",3,"...*.**."
  651.         
  652.         
  653.                                 PAGE 244
  654.         
  655. -----------------------------------------------------------------------------
  656.         
  657.         
  658.             NewD "A",4,"..*****."
  659.             NewD "A",5,".*....*."
  660.             NewD "A",6,"***..***"
  661.             NewD "A",7,""
  662.             
  663.             ActivateFont "ralfi"
  664.             '* Second character using byte value method (faster)
  665.             
  666.             NewB "@",0,126
  667.             NewB "@",1,129
  668.             NewB "@",2,157
  669.             NewB "@",3,161
  670.             NewB "@",4,161
  671.             NewB "@",5,157
  672.             NewB "@",6,129
  673.             NewB "@",7,126
  674.             
  675.             '* Sample text
  676.             ActivateFont "tobi"
  677.             PRINT "@ 1989 Abacus (Alliance) - Amiga Graphics Inside &
  678.      out "
  679.             PRINT "       ^                   ^ "
  680.             ActivateFont "ralfi"
  681.             PRINT "@ 1989 Abacus (Alliance) - Amiga Graphics Inside
  682.     & out "
  683.             PRINT "^"
  684.             
  685.             '* Delete font
  686.             '* Call:
  687.             '*   DeleteFont "name"
  688.             
  689.             DeleteFont "tobi"
  690.             DeleteFont "ralfi"
  691.             END
  692.             
  693.             
  694.     SUB ActivateFont(z.n$) STATIC
  695.             z.name$  = UCASE$(z.n$+".font"+CHR$(0))
  696.             t&(0)    = SADD(z.name$)
  697.             t&(1)    = 8*2^16
  698.             font&    = OpenFont&(VARPTR(t&(0)))
  699.             IF font& = 0 THEN BEEP: EXIT SUB
  700.             CALL CloseFont(font&)
  701.             CALL SetFont(WINDOW(8),font&)
  702.     END SUB
  703.         
  704.         
  705.     SUB NewB(char$,row%,value%) STATIC
  706.             n.font&       = PEEKL(WINDOW(8)+52)
  707.             n.data&       = PEEKL(n.font&+34)
  708.             n.ascii&      = ASC(char$)
  709.             n.lo%         = PEEK(n.font&+32)
  710.             n.hi%         = PEEK(n.font&+33)
  711.             n.modulo%     = PEEKW(n.font&+38)
  712.             n.offset%     = (n.ascii%-n.lo%)+row%*n.modulo%
  713.             n.data%       = 0
  714.             
  715.             IF n.ascii%<n.lo% OR n.ascii%>n.hi% THEN
  716.         
  717.         
  718.                             PAGE 245
  719.        
  720. -----------------------------------------------------------------------------
  721.        
  722.        
  723.            PRINT "Character not in font!"
  724.            ERROR 255
  725.        END IF
  726.            
  727.        POKE n.data&+n.offset%,value%
  728.     END SUB
  729.        
  730.     SUB NewD(char$,row%,bit$) STATIC
  731.        n.font&     = PEEKL(WINDOW(8)+52)
  732.        n.data&     = PEEKL(n.font&+34)
  733.        n.ascii%    = ASC(char$)
  734.        n.lo%       = PEEK(n.font&+32)
  735.        n.hi%       = PEEK(n.font&+33)
  736.        n.modulo%   = PEEKW(n.font&+38)
  737.        n.offset%   = (n.ascii%-n.lo%)+row%*n.modulo%
  738.        n.data%     = 0
  739.        
  740.        IF n.ascii%<n.lo% OR n.ascii%>n.hi% THEN
  741.            PRINT "Character not in font!"
  742.            ERROR 255
  743.        END IF
  744.        
  745.        '* 8 bit alignment
  746.        IF LEN(bit$)<>8 THEN
  747.            IF LEN(bit$)>8 THEN bit$ = LEFT$(bit$,8)
  748.            IF LEN(bit$)<8 THEN bit$ = bit$+space$(8-LEN(bit$))
  749.        END IF
  750.        
  751.        '* Write data in chardata.
  752.        FOR loop1%=7 TO 0 STEP -1
  753.            n.check$ = MID$(bit$,8-loop1%,1)
  754.            IF n.check$ = "*" THEN
  755.                 n.data%   = n.data%+2^loop1%
  756.            END IF
  757.        NEXT loop1%
  758.        POKE n.data&+n.offset%,n.data%
  759.     END SUB
  760.        
  761.     SUB DeleteFont (z.n$) STATIC
  762.        z.name$ = UCASE$(z.n$+".font"+CHR$(0))
  763.        t&(0)   = SADD(z.name$)
  764.        t&(1)   = 8*2^16
  765.        font&   = OpenFont&(VARPTR(t&(0)))
  766.        IF font&= 0 THEN ERROR 255
  767.        
  768.        z.size& = PEEKL(font&-4)
  769.        IF z.size&<100 OR z.size&>4000 THEN ERROR 255
  770.               
  771.        '* Remove from system list.
  772.        z.1&    = PEEKL(font&)
  773.        z.2&    = PEEKL(font&+4)
  774.        POKEL z.1&+4,z.2&
  775.        POKEL z.2&,z.1&
  776.        
  777.        '* Release RAM
  778.                      
  779.               
  780.                             PAGE 246
  781.        
  782. -----------------------------------------------------------------------------
  783.  
  784.  
  785.        font& = font& - 4
  786.        CALL FreeMem(font&,z.size&)
  787.        
  788.        '* Load standard font
  789.        standard$  = "topaz.font"+CHR$(0)
  790.        t&(0)      = SADD(standard$)
  791.        font&      = OpenFont&(VARPTR(t&(0)))
  792.        IF font&   = 0 THEN ERROR 255
  793.        CALL SetFont(WINDOW(8),font&)
  794.     END SUB
  795.        
  796.     SUB MakePrgFont(z.n$,ascii.lo%,ascii.hi%) STATIC
  797.        z.name$     = UCASE$(z.n$+".font"+CHR$(0))
  798.        z.count%    = ascii.hi% - ascii.lo%=2
  799.        z.modulo%   = z.count%
  800.        z.size&     = z.count%*8+z.count%*4+110
  801.        z.offset%   = ascii.lo%-32
  802.        z.begin%    = 0
  803.        
  804.        mem.opt&    = 2^0+2^16
  805.        z.add&      = AllocMem(z.size&,mem.opt&)
  806.        IF z.add&   = 0 THEN ERROR 7
  807.        POKEL z.add&,z.size&
  808.        z.add&      = z.add& + 4
  809.        
  810.        z.data&     = z.add& + 100
  811.        z.loc&      = z.data&+z.count%*8
  812.        z.name&     = z.add&+65
  813.        
  814.        POKEL z.add&+10,z.name&
  815.        POKEW z.add&+18,z.size&-4
  816.        POKEW z.add&+20,8
  817.        POKE z.add&+23,64
  818.        POKEW z.add&+24,8
  819.        POKEW z.add&+26,6
  820.        POKE  z.add&+32,ascii.lo%
  821.        POKE  z.add&+33,ascii.hi%
  822.        POKEL z.add&+34,z.data&
  823.        POKEW z.add&+38,z.modulo%
  824.        POKEL z.add&+40,z.loc&
  825.        
  826.        '* Fill Name field.
  827.            FOR loop1% = 1 TO LEN(z.name$)
  828.                POKE z.name$+loop1%-1,ASC(MID$(z.name$,loop1%,1))
  829.            NEXT loop1%
  830.        
  831.        '* charLoc field
  832.        FOR loop1% = 0 TO z.count%-1
  833.            POKEW z.loc&+(4*loop1%)+0,loop1%*8
  834.            POKEW z.loc&+(4*loop1%)+2,8
  835.        NEXT loop1%
  836.        
  837.        '* charData field.
  838.        sample$ = "topaz.font"+CHR$(0)
  839.        t&(0)   = SADD(sample$)
  840.        
  841.        
  842.                             PAGE 247
  843.        
  844. -----------------------------------------------------------------------------
  845.        
  846.        
  847.        t&(1)    = 8*2^16
  848.        sample&  = OpenFont&(VARPTR(t&(0)))
  849.        IF sample& = 0 THEN
  850.            PRINT "ROM-fonts weg???!"
  851.            ERROR 255
  852.        END IF
  853.        s.char&    = PEEKL(sample&+34)
  854.        s.modulo%  = PEEKW(sample&+38)
  855.        CALL CloseFont(sample&)
  856.        
  857.        IF z.offset%<0 THEN
  858.            z.count%   = z.count%+z.offset%
  859.            z.begin%   = ABS(z.offset%)
  860.            z.offset%  = 0
  861.        END IF
  862.        
  863.        FOR loop1% = 0 TO 7
  864.            CALL CopyMem(s.char&+z.offset%+loop1%*s.modulo%, z.data&+
  865.     z.begin%+loop1%*z.modulo%,z.count%-1)
  866.        NEXT loop1%
  867.        
  868.        '* Unprintable character.
  869.        POKE z.data&+z.modulo%-1+0*z.modulo%,224
  870.        POKE z.data&+z.modulo%-1+1*z.modulo%,64
  871.        POKE z.data&+z.modulo%-1+2*z.modulo%,64
  872.        POKE z.data&+z.modulo%-1+3*z.modulo%,64
  873.        POKE z.data&+z.modulo%-1+4*z.modulo%,73
  874.        POKE z.data&+z.modulo%-1+5*z.modulo%,73
  875.        POKE z.data&+z.modulo%-1+6*z.modulo%,77
  876.        POKE z.data&+z.modulo%-1+7*z.modulo%,74
  877.        
  878.        '* Link
  879.        CALL AddFont(z.add&)
  880.        t&(0)      = SADD(z.name$)
  881.        font.new&  = OpenFont&(VARPTR(t&(0)))
  882.        IF font.new& = 0 THEN ERROR 255
  883.        
  884.        CALL SetFont(WINDOW(8),font.new&)
  885.     END SUB
  886.  
  887.  
  888. Altogether this program provides you with five SUB programs:
  889.        
  890.        * MakePrgFont
  891.        * DeleteFont
  892.        * NewD
  893.        * NewB
  894.        * ActivateFont                     
  895.                             
  896. MakePrgFont:
  897. -----------                     
  898.  
  899. This SUB program allows you to create a completely new font which carries
  900. the name assigned by you. Here is the call:
  901.        
  902.        MakePrgFont name$,lo%,hi%
  903.  
  904.        name$   : Name of new font.
  905.        lo%     : ASCII value of first character
  906.        hi%     : ASCII value of last character.
  907.                             
  908.                             
  909.                             PAGE 248
  910.        
  911. -----------------------------------------------------------------------------
  912.        
  913.        
  914. You determine the number of characters in your font. Every value has
  915. an ASCII character that can be determined using the ASC function. Select
  916. the low and high limits.
  917.        
  918.        LINE INPUT "Character ";z$
  919.        PRINT ASC(z$)
  920.        
  921. The codes 0 TO 255 are available.              
  922.                             
  923. After the font is prepared, it contains no character definitions. Basically,
  924. it is 'empty'; all the current characters equal nothing. Because of this we
  925. will fill the new font with the data from the ROM font topaz 8.
  926.                             
  927. After this call the new font is ready for your commands. All the characters
  928. within your ASCII limits will be displayed with 'topaz8' characters.
  929. Any character outside these limits will be displayed as an 'unprintable
  930. character' with the small TW character.                     
  931.                             
  932.               
  933. Actviate Font:
  934. -------------
  935.        
  936. This SUB program is useless to you if you only want to work with a single
  937. font. However, if you wish to work with many fonts with different names,
  938. you can select any of them with this command.
  939.        
  940.        ActivateFont name$
  941.        
  942.        name$  : The name of a previously generated font with MakePrgFont.
  943.        
  944.        
  945. NewD:
  946. ----       
  947.        
  948. Our goal was to define our own characters. This is accomplished with NewD.
  949. Each character of our font is 8 pixels wide and 8 pixels high. By using 
  950. NewD, we can define any one of the eight rows of any character.
  951.        
  952.        NewD  char$,nr%,bit$
  953.        
  954.        char$   : The character that you want to define.
  955.        nr%     : The row of the character (0-7)
  956.        bit$    : The new data row (*=set pixels, "." unused pixels)
  957.        
  958. NOTE: NewD defines a character from the last generated (or active) font.
  959.       Obviously the character must exist in the font in order to be 
  960.       redefined.
  961.                             
  962.                             
  963.                             PAGE 249
  964.        
  965. -----------------------------------------------------------------------------
  966.        
  967.        
  968. NewB
  969. ----              
  970.        
  971. This is a variation of the NewD. When using NewD the character data for the
  972. new character is displayed as astericks and points in binary form. This 
  973. binary data must first be converted to decimal. However, if you are 
  974. familiar with the binary decimal conversion, you can use the decimal values
  975. directly. In order to do this, NewB is used.       
  976.        
  977.        NewB char$,nr%,value%
  978.        
  979.        char$,nr% : Same as with NewD
  980.        value%    : Decimal value for row (0 to 255).
  981.        
  982.        
  983. DeleteFont
  984. ----------
  985.  
  986. When you no longer need one of your open fonts, you must close it again.
  987. This is accomplished with the command:
  988.        
  989.        DeleteFont name$
  990.        
  991.        name$     : Name of the font opened using MakePrgFont.
  992.  
  993. At the end of your program you must close all of the fonts that were opened
  994. using MakePrgFont. This returns the assigned memory to the system.
  995.        
  996. Those of you who want or need more information of making your own fonts 
  997. will fint detailed explanations on the following pages.       
  998.        
  999.        
  1000. MakePrgFont
  1001. -----------
  1002.  
  1003. We fill the TextFont structure (from section 5.5) with all the required 
  1004. parameters. Then we initialise the field CharLoc with its required 
  1005. parameters. Because the characters of the font have a standard width value
  1006. of 8 pixels, the offset value is a multiple of 8. The width value is always
  1007. equal to 8 (see section 5.5).
  1008.        
  1009. The charData field is supposed to be filled with the use defined characters.
  1010. Since we assume that not all the characters will be redefined, we fill the
  1011. font with the ROM font topaz 8. After opening topaz 8, we save the pointer
  1012. to it in the variable sample&. The MODULO is also read. Now we can close
  1013. topaz again because the charData is in ROM and cannot be lost.
  1014.  
  1015.  
  1016.        
  1017. Next we must initialise two varaibles z.offset% and z.begin%. Your font 
  1018. wont always have the same contents as the ROM type. The number of the
  1019. character that the new font will later begin with is contained in the 
  1020. z.offset%. The ROM font always starts with ASCII code 32. If the first
  1021. character in your font has a larger value, for example "A" (code = 65),
  1022. then z.offset% contains 65-32 = 33. The opposite is accomplished with 
  1023. z.begin%. If the ASCII code of the first character in your new font is 
  1024. smaller than 32, then z.begin% contains the difference between the new
  1025. values.
  1026.        
  1027.        
  1028.                             PAGE 250
  1029.        
  1030. -----------------------------------------------------------------------------
  1031.        
  1032.        
  1033. Now we can copy the ROM data to the RAM buffer. For this we use a function 
  1034. of the exec.library:
  1035.        
  1036.        CALL CopyMem(o.data&,z.data&,bytes&)
  1037.        
  1038.        o.data&:   Original data.
  1039.        z.data&:   Target data.
  1040.        bytes& :   Number of bytes to copy.       
  1041.        
  1042. This routine was first made available in Kickstart Version 1.2. Users of 
  1043. older versions must either revise these commands into PEEKS and POKES 
  1044. or completely leave out the loop. Otherwise you have to define all the 
  1045. characters of the new font before working with it.       
  1046.        
  1047. After all the characters are copied, the shape of the unprintable character
  1048. is defined as a small "TW". Whenever a user requests a characte that doesnt
  1049. exist in the font, the "TW" character will appear. The data for this 
  1050. unprintable character us stored after the data for all the other characters.
  1051.        
  1052. Now the new font is completely functional. To add this font to the system,
  1053. we use the function AddFont. From this point on, other programs can also
  1054. access your font (for example the NOTEPAD). Finally we use OpenFont& to
  1055. open the new font. The address font.new& must match the address z.add&.
  1056.        
  1057. Right now it is necessary to take a closer look at the beginning of the 
  1058. TextFont structure. The message structure looks like this:
  1059.        
  1060. Data structure Message/exec/20 bytes.
  1061.        
  1062. Offset  Type    Description.
  1063. ------- ------- -------------------------------------------------
  1064. +000    Long    Pointer to the next font.
  1065. +004    Long    Pointer to the previous font.
  1066. +008    Byte    Node Type.
  1067. +009    Byte    Priority.
  1068. +010    Long    Pointer to the name of the font.
  1069. +014    Long    Pointer to ReplyPort.
  1070. +018    Word    Length of Message.
  1071.        
  1072. Before we call the AddFont routine, we must store the name field and length
  1073. of the message, which equals the length of the font. After AddFont, the 
  1074. rest of the pointers are initialised, which means that the first two 
  1075. pointers point at different fonts.       
  1076.        
  1077. This step is very important when you try to delete your font from the 
  1078. system again. This will be explained further in DeleteFont.       
  1079.        
  1080.        
  1081.                             PAGE 251
  1082.        
  1083. -----------------------------------------------------------------------------
  1084.        
  1085.        
  1086. ActivateFont
  1087. ------------
  1088.  
  1089. Here we search for the font with the requested name. This SUB can be only
  1090. used to look for fonts that are created with MakePrgFont. The reason for
  1091. this is that the font is only opened for a short time, in order to receive
  1092. all the necessary pointers, and then closed again. We do not have to keep
  1093. it open because it has already been opened with MakePrgFont.
  1094.        
  1095.        
  1096. SetFont
  1097. -------
  1098.        
  1099. This SUB program activates the font.
  1100.        
  1101.        
  1102. NewD, NewB
  1103. ----------
  1104.        
  1105. We read all the required font data from the RastPort. NewD converts the bit
  1106. definitions into a decimal number and therefore, is faster. The values are
  1107. poked to the locations set by your parameters.       
  1108.        
  1109.        
  1110. DeleteFont
  1111. ----------       
  1112.        
  1113. The name font is opened here also. Fonts must always be removed by whatever
  1114. opened them. ROM fonts are never removed and disk fonts are loaded and
  1115. handled by AmigaDOS. You are responsible for the cleanup of your own
  1116. fonts. When reserving the memory, MakePrgFont stored the length of the 
  1117. font in the last 4 bytes before the font. We read out this value. Before 
  1118. we delete the font with FreeMem, we must correct the Systemlist because
  1119. AddFont integrated our font with the SystemList. The required fields are
  1120. restored and our font evaporates.
  1121.        
  1122. Now we can release the RAM allocated for the font and return this memory
  1123. to the system. To avoid being left without a font, we activate the ROM 
  1124. font again.       
  1125.        
  1126.                             
  1127.               ----------------------------------------------
  1128.        
  1129. 5.5.4 A PROPORTIONAL FONT.
  1130.        
  1131. Now we will discuss the complex proportional font. It is almost impossible, 
  1132. in this type of font, to redefine existing characters. Every time we 
  1133. redefine one character, hundreds of bytes would have to be shifted one way
  1134. or the other to adjust for the new character size. A solution to this 
  1135. problem is to provide a number for the maximum width of any single 
  1136. character. The program then reserves enough memory for a font containing
  1137. characters of this size. Although this method isn't memory efficient, it 
  1138. is the only practical solution.       
  1139.        
  1140. Again, our character generator demonstrates it's user friendliness. You
  1141. can easily create characters without being required to use any complex 
  1142. numbers and parameters. We use six SUB programs:
  1143.        
  1144.        MakePrgFont
  1145.        DeleteFont
  1146.        NewB
  1147.        NewD
  1148.        ActivateFont
  1149.        Set
  1150.        
  1151.               
  1152.                             PAGE 252
  1153.        
  1154. -----------------------------------------------------------------------------
  1155.        
  1156.        
  1157. You are already familiar with these names. The way these SUB programs work
  1158. is very similar to those in the fixed width character generator from the 
  1159. previous chapter.       
  1160.        
  1161. Again, you can create as many fonts as you like. To do this use the 
  1162. following command:
  1163.        
  1164.        MakePrgFont name$,lo%,hi%,width%,height%,base%
  1165.        
  1166.        name$       : Name of font.
  1167.        lo%         : Lower ASCII limit (See chapter 5.5.3)
  1168.        hi%         : Upper ASCII limit.
  1169.        width%      : Maximum width in pixels.
  1170.        height%     : Uniform height in pixels.
  1171.        base%       : Baseline (height without underline).
  1172.        
  1173. NOTE: 
  1174. ----
  1175.        
  1176. Baseline must be at least one pixel smaller than height%, otherwise, while 
  1177. using algorithmic managed fonts (special italic), the system buffer can be
  1178. overwritten.       
  1179.        
  1180. After this call, the Amiga generates a font with the above parameters; no
  1181. other information is required. This font is exactly the opposite from those
  1182. enerated with the fixed width generator because it is empty with no 
  1183. previoulsy defined characters. Now it is your responsibility to define each
  1184. character in the font.
  1185.        
  1186. Before you design a particular character using the familiar SUB programs
  1187. NewD and NewB, you must specify and individual size for this character.
  1188. This is accomplished by using the "set" command:
  1189.        
  1190.        Set char$,spacing%,kerning%
  1191.        
  1192.        char$      : The character for which this value applies.
  1193.        spacing%   : Width of character (cannot exceed the maximum width
  1194.                     of the font generated).
  1195.        kerning%   : Number of pixels to skip before the character you 
  1196.                     actually define appears.
  1197.        
  1198. Additional information can be found in section 5.5
  1199.        
  1200.        
  1201.                             PAGE 253
  1202.        
  1203. -----------------------------------------------------------------------------
  1204.        
  1205.        
  1206. All the other SUB programs have similar functions to those in the fixed 
  1207. width generator. However, they are not identical.
  1208.        
  1209.        
  1210.         '############################################
  1211.         '#
  1212.         '# Section: 5.5.4
  1213.         '# Program: Proportional font generator.
  1214.         '# Date   : 04/12/87
  1215.         '# Author : tob
  1216.         '# Version: 1.0
  1217.         '#
  1218.         '##############################################
  1219.         
  1220.        ' This program makes it possible to create differently named
  1221.        ' proportional fonts and every character  can have its own 
  1222.        ' individual width. Undefined characters will not have character
  1223.        ' data, and will appear only after being successfully defined.
  1224.         
  1225.         PRINT "Searching for .bmap file ......"
  1226.         
  1227.         'GRAPHICS-library
  1228.         DECLARE FUNCTION OpenFont& LIBRARY
  1229.         'CloseFont()
  1230.         'SetFont()
  1231.         'AddFont()
  1232.         
  1233.         'EXEC-library
  1234.         DECLARE FUNCTION AllocMem& LIBRARY
  1235.         'FreeMem()
  1236.         
  1237.         LIBRARY "graphics.library"
  1238.         LIBRARY "exec.library"
  1239.         
  1240.         init:
  1241.            '* Generate fonts
  1242.            MakePrgFont "tobi",32,65,9,10,7
  1243.  
  1244.            '* Set format
  1245.            '* Set "character$",space,kern
  1246.            
  1247.            Set "@",20,3
  1248.            NewD "@",0,"...***..."
  1249.            NewD "@",1,"..*...*.."
  1250.            NewD "@",2,"......*.."
  1251.            NewD "@",3,".....*..."
  1252.            NewD "@",4,"....*...."
  1253.            NewD "@",5,"....*...."
  1254.            NewD "@",6,"........."
  1255.            NewD "@",7,"*********"
  1256.            NewD "@",8,".*******."
  1257.            NewD "@",9,"..*****.."
  1258.         
  1259.            'Second character using byte method.
  1260.             
  1261.        
  1262.                             PAGE 254
  1263.        
  1264. -----------------------------------------------------------------------------
  1265.             
  1266.            Set "A",11,1
  1267.            NewB "A",0,8,126
  1268.            NewB "A",1,8,129
  1269.            NewB "A",2,8,157
  1270.            NewB "A",3,8,161
  1271.            NewB "A",4,8,161
  1272.            NewB "A",5,8,157
  1273.            NewB "A",6,8,129
  1274.            NewB "A",7,8,126
  1275.             
  1276.             '* Sample text
  1277.            PRINT STRING$(40,"A")
  1278.            PRINT STRING$(40,"@")
  1279.        
  1280.             '* Delete font
  1281.             '* Call:
  1282.             '*   DeleteFont "name"
  1283.             
  1284.             DeleteFont "tobi"
  1285.             END
  1286.             
  1287.             
  1288.     SUB ActivateFont(z.n$) STATIC
  1289.             z.name$  = UCASE$(z.n$+".font"+CHR$(0))
  1290.             t&(0)    = SADD(z.name$)
  1291.             t&(1)    = 8*2^16
  1292.             font&    = OpenFont&(VARPTR(t&(0)))
  1293.             IF font& = 0 THEN BEEP: EXIT SUB
  1294.             CALL CloseFont(font&)
  1295.             CALL SetFont(WINDOW(8),font&)
  1296.     END SUB
  1297.         
  1298.     SUB Set(char$,spacing%,kerning%) STATIC
  1299.        n.font&       = PEEKL(WINDOW(8)+52)
  1300.        n.space&      = PEEKL(n.font&+44)
  1301.        n.kern&       = PEEKL(n.font&+48)
  1302.        n.ascii%      = ASC(char$)
  1303.        n.lo%         = PEEK(n.font&+32)
  1304.        n.hi%         = PEEK(n.font&+33)
  1305.        n.number%     = n.ascii% - n.lo%
  1306.        IF n.ascii%<n.lo% OR n.ascii%>n.hi% THEN
  1307.            EXIT SUB
  1308.        END IF
  1309.        POKEW n.space&+(2*n.number%),spacing%
  1310.        POKEW n.kern&+(2*n.number%),kerning%
  1311.     END SUB
  1312.         
  1313.     SUB NewB(char$,row%,bits%,value%) STATIC
  1314.             n.byte%    = 0
  1315.             n.bit%     = 0
  1316.             n.font&       = PEEKL(WINDOW(8)+52)
  1317.             n.data&       = PEEKL(n.font&+34)
  1318.             n.loc&        = PEEKL(n.font&+40)
  1319.             n.ascii&      = ASC(char$)
  1320.             n.lo%         = PEEK(n.font&+32)
  1321.             n.hi%         = PEEK(n.font&+33)
  1322.             n.modulo%     = PEEKW(n.font&+38)
  1323.             n.offset%     = row%*n.modulo%
  1324.             n.height%     = PEEKW(n.font&+20)
  1325.        
  1326.        
  1327.                             PAGE 255
  1328.        
  1329. -----------------------------------------------------------------------------
  1330.        
  1331.        
  1332.            n.number%      = n.ascii%-n.lo%
  1333.            n.width%       = PEEKW(PEEKL(n.font&+40)+(4*n.number%)+2)
  1334.            n.offset&      = PEEKW(PEEKL(n.font&+40)+(4*n.number%))
  1335.            n.byte%        = INT(n.offset&/8)
  1336.            n.bit%         = 7-(n.offset&-(n.byte%*8))
  1337.        
  1338.            IF n.ascii%<n.lo% OR n.ascii%>n.hi% THEN
  1339.               EXIT SUB
  1340.            END IF
  1341.            
  1342.            IF bits%>n.width% THEN
  1343.                bits% = n.width%
  1344.            END IF
  1345.            n.data&        = n.data&+n.offset%
  1346.            FOR loop1% = bits%-1 TO 0 STEP -1
  1347.                IF (value% AND 2^loop1%)<>0 THEN
  1348.                    POKE n.data&+n.byte%,PEEK(n.data&+n.byte%) OR (2^n.bit%)
  1349.                END IF
  1350.                n.bit% = n.bit% - 1
  1351.                IF n.bit% < 0 THEN
  1352.                    n.bit% = 7
  1353.                    n.byte% = n.byte% + 1
  1354.                END IF
  1355.            NEXT loop1%
  1356.            
  1357.            POKEW n.loc&+(4*n.number%)+2,bits%
  1358.     END SUB
  1359.        
  1360.     SUB NewD(char$,row%,bit$) STATIC
  1361.            bits%        = LEN(bits$)
  1362.            n.byte%      = 0
  1363.            n.bit%       = 0
  1364.        n.font&     = PEEKL(WINDOW(8)+52)
  1365.        n.data&     = PEEKL(n.font&+34)
  1366.        n.loc&      = PEEKL(n.font&+40)
  1367.        n.ascii%    = ASC(char$)
  1368.        n.lo%       = PEEK(n.font&+32)
  1369.        n.hi%       = PEEK(n.font&+33)
  1370.        n.modulo%   = PEEKW(n.font&+38)
  1371.        n.offset%   = row%*n.modulo%
  1372.        n.height%   = PEEKW(n.font&+20)
  1373.        n.number%   = n.ascii%-n.lo%
  1374.        n.width%    = PEEKW(PEEKL(n.font&+40)+(4*n.number%)+2)
  1375.        n.offset&   = PEEKW(PEEKL(n.font&+40)+(4*n.number%))
  1376.        n.byte%     = INT(n.offset&/8)
  1377.        n.bit%      = 7-(n.offset&-(n.byte%*8))
  1378.        
  1379.        IF n.ascii%<n.lo% OR n.ascii%>n.hi% THEN
  1380.            EXIT SUB
  1381.        END IF
  1382.        
  1383.        IF bits% > n.width% THEN
  1384.            bits% = n.width%
  1385.        END IF
  1386.        
  1387.        
  1388.                             PAGE 256
  1389.        
  1390. -----------------------------------------------------------------------------
  1391.        
  1392.        
  1393.        n.data& = n.data& + n.offset%
  1394.        FOR loop1%=bits%-1 TO 0 STEP -1
  1395.            c$ = MID$(bits$,bits%-loop1%,1)
  1396.            IF c$ = "" THEN
  1397.                POKE n.data&+n.byte%,PEEK(n.data&+n.byte%) OR (2^n.bit%)
  1398.            END IF
  1399.            n.bit% = n.bit% - 1
  1400.            IF n.bit% < 0 THEN
  1401.                n.bit% = 7
  1402.                n.byte% = n.byte%+1
  1403.            END IF
  1404.        NEXT loop1%
  1405.        
  1406.        POKEW n.loc&+(4*n.number%)+2,bits%
  1407.     END SUB
  1408.        
  1409.     SUB DeleteFont (z.n$) STATIC
  1410.        z.name$ = UCASE$(z.n$+".font"+CHR$(0))
  1411.        t&(0)   = SADD(z.name$)
  1412.        t&(1)   = 8*2^16
  1413.        font&   = OpenFont&(VARPTR(t&(0)))
  1414.        IF font&= 0 THEN ERROR 255
  1415.        
  1416.        z.size& = PEEKL(font&-4)
  1417.        IF z.size&<100 OR z.size&>40000& THEN ERROR 255
  1418.               
  1419.        '* Remove from system list.
  1420.        z.1&    = PEEKL(font&)
  1421.        z.2&    = PEEKL(font&+4)
  1422.        POKEL z.1&+4,z.2&
  1423.        POKEL z.2&,z.1&
  1424.        
  1425.        '* Release RAM
  1426.                      
  1427.        font& = font& - 4
  1428.        CALL FreeMem(font&,z.size&)
  1429.        
  1430.        '* Load standard font
  1431.        standard$  = "topaz.font"+CHR$(0)
  1432.        t&(0)      = SADD(standard$)
  1433.        font&      = OpenFont&(VARPTR(t&(0)))
  1434.        IF font&   = 0 THEN ERROR 255
  1435.        CALL SetFont(WINDOW(8),font&)
  1436.     END SUB
  1437.        
  1438.     SUB MakePrgFont(z.n$,ascii.lo%,ascii.hi%,z.maxX%,z.height%,
  1439. z.baseline%) STATIC
  1440.        z.name$     = UCASE$(z.n$+".font"+CHR$(0))
  1441.        z.number%   = ascii.hi%-ascii.lo%+2
  1442.        z.modulo%   = (z.number%*z.maxX%+4)/8
  1443.        IF (z.modulo% MOD 2) <> 0 THEN
  1444.            z.modulo% = z.modulo%+1
  1445.        END IF
  1446.        
  1447.        
  1448.                             PAGE 257
  1449.        
  1450. -----------------------------------------------------------------------------
  1451.        
  1452.        
  1453.        z.size& = z.modulo%*z.height%+z.number%*8+110
  1454.        
  1455.        IF z.baseline%>z.height% THEN
  1456.            z.baseline% = z.height%-1
  1457.        END IF
  1458.            
  1459.        mem.opt&    = 2+0+2^16
  1460.        z.add&      = AllocMem(z.size&,mem.opt&)
  1461.        IF z.add& = 0 THEN ERROR 7
  1462.        POKEL z.add&,z.size&
  1463.        
  1464.        z.add&     = z.add&+4
  1465.        z.data&    = z.add&+100
  1466.        z.loc&     = z.data&+z.modulo%*z.height%
  1467.        IF z.loc&/2<>INT(z.loc&/2) THEN
  1468.            z.loc& = z.loc&+1
  1469.        END IF
  1470.        
  1471.        z.kern&    = z.loc&+4*z.number%
  1472.        z.space&   = z.kern&+2*z.number%
  1473.        z.name&    = z.add&+65
  1474.        
  1475.        POKEL z.add&+10,z.name&
  1476.        POKEW z.add&+18,z.size&-4
  1477.        POKEW z.add&+20,z.height%
  1478.        POKE  z.add&+23,64+32
  1479.        POKEW z.add&+24,z.maxX%
  1480.        POKEW z.add&+26,z.baseline%
  1481.        POKE  z.add&+32,ascii.lo%
  1482.        POKE  z.add&+33,ascii.hi%
  1483.        POKEL z.add&+34,z.data&
  1484.        POKEW z.add&+38,z.modulo%
  1485.        POKEL z.add&+40,z.loc&
  1486.        POKEL z.add&+44,z.space&
  1487.        POKEL z.add&+48,z.kern&
  1488.        
  1489.        '* Fill Name Field.
  1490.        FOR loop1%=1 TO LEN(z.name$)
  1491.            POKE z.name&+loop1%-1,ASC(MID$(z.name$,loop1%,1))
  1492.        NEXT loop1%
  1493.        
  1494.        '* charLoc field
  1495.        FOR loop1% = 0 TO z.number%-1
  1496.            POKEW z.loc&+(4*loop1%)+0,loop1%*z.maxX%
  1497.            POKEW z.loc&+(4*loop1%)+2,maxX%
  1498.        NEXT loop1%
  1499.        
  1500.        '* Link
  1501.        CALL AddFont(z.add&)
  1502.        t&(0)      = SADD(z.name$)
  1503.        font.new&  = OpenFont&(VARPTR(t&(0)))
  1504.        IF font.new& = 0 THEN ERROR 255
  1505.        
  1506.        CALL SetFont(WINDOW(8),font.new&)
  1507.     END SUB
  1508.        
  1509.        
  1510.                                    PAGE 258
  1511.        
  1512. -----------------------------------------------------------------------------
  1513.  
  1514.  
  1515.  
  1516.